﻿using System;
using System.Globalization;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;


namespace advadev.DataStorage
{

    /// <summary>
    /// Represents a generic entity
    /// </summary>
    [DataContract]
    sealed public class GenericEntity
    {

        /// <summary>for internal use</summary>
        private IGenericObject _genericObject;
        /// <summary>for internal use</summary>
        [DataMember]
        private string _entityId = string.Empty;
        /// <summary>for internal use</summary>
        [DataMember]
        private string _applicationKey = string.Empty;
        /// <summary>for internal use</summary>
        [DataMember]
        private string _fullClassName = string.Empty;
        /// <summary>for internal use</summary>
        [DataMember]
        private XElement _xmlSerialization;


        /// <summary>
        /// Initializes a new instance of the GenericEntity class
        /// </summary>
        public GenericEntity()
        {
        }

        /// <summary>
        /// Initializes a new instance of the GenericEntity class by the given parameter
        /// </summary>
        /// <param name="genericObject">
        /// Generic object
        /// </param>
        /// <param name="applicationKey">
        /// Application key
        /// </param>
        public GenericEntity(IGenericObject genericObject, string applicationKey)
        {
            EntityId = genericObject.GenericObjectId;
            ApplicationKey = applicationKey;
            FullClassName = genericObject.GetType().FullName;
            XmlSerialization = serialize(genericObject);
            _genericObject = genericObject;
        }


        /// <summary>
        /// Gets or sets the entity id
        /// </summary>
        public string EntityId
        {
            get
            {
                return _entityId;
            }
            set
            {
                _entityId = value;
            }
        }

        /// <summary>
        /// Gets or sets the application key
        /// </summary>
        public string ApplicationKey
        {
            get
            {
                return _applicationKey;
            }
            set
            {
                _applicationKey = value;
            }
        }

        /// <summary>
        /// Gets or sets the full class name
        /// </summary>
        public string FullClassName
        {
            get
            {
                return _fullClassName;
            }
            set
            {
                _fullClassName = value;
            }
        }

        /// <summary>
        /// Gets or sets the xml serialization
        /// </summary>
        public XElement XmlSerialization
        {
            get
            {
                return _xmlSerialization;
            }
            set
            {
                _xmlSerialization = value;
            }
        }


        /// <summary>
        /// Gets the generic object
        /// </summary>
        /// <param name="type">
        /// Type of the generic object
        /// </param>
        /// <returns>
        /// The generic object or null
        /// </returns>
        public IGenericObject CreateGenericObject(Type type)
        {
            if (_genericObject == null)
            {
                _genericObject = deserialize(XmlSerialization, type);
            }
            return _genericObject;
        }


        #region serialization
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        static private XElement serialize(IGenericObject genericObject)
        {
            try
            {
                using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
                {
                    using (XmlWriter xmlWriter = XmlWriter.Create(writer))
                    {
                        XmlSerializer serializer = new XmlSerializer(genericObject.GetType());
                        serializer.Serialize(xmlWriter, genericObject);
                        return XElement.Parse(writer.ToString());
                    }
                }
            }
            catch (Exception)
            {
                return null;
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        static private IGenericObject deserialize(XElement xElement, Type type)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(type);
                return serializer.Deserialize(xElement.CreateReader()) as IGenericObject;
            }
            catch (Exception)
            {
                return null;
            }
        }
        #endregion serialization

    }

}
